<script>
    import ElCheckbox from 'element-ui/packages/checkbox';
    import ElRadio from 'element-ui/packages/radio';
    import {isEqual} from 'element-ui/src/utils/util';

    const stopPropagation = e => e.stopPropagation();

    export default {
        inject: ['panel'],

        components: {
            ElCheckbox,
            ElRadio
        },

        props: {
            node: {
                required: true
            },
            nodeId: String
        },

        computed: {
            config() {
                return this.panel.config;
            },
            isLeaf() {
                return this.node.isLeaf;
            },
            isDisabled() {
                return this.node.isDisabled;
            },
            checkedValue() {
                return this.panel.checkedValue;
            },
            isChecked() {
                return this.node.isSameNode(this.checkedValue);
            },
            inActivePath() {
                return this.isInPath(this.panel.activePath);
            },
            inCheckedPath() {
                if (!this.config.checkStrictly) return false;

                return this.panel.checkedNodePaths
                    .some(checkedPath => this.isInPath(checkedPath));
            },
            value() {
                return this.node.getValueByOption();
            }
        },

        methods: {
            handleExpand() {
                const {panel, node, isDisabled, config} = this;
                const {multiple, checkStrictly} = config;

                if (!checkStrictly && isDisabled || node.loading) return;

                if (config.lazy && !node.loaded) {
                    panel.lazyLoad(node, () => {
                        // do not use cached leaf value here, invoke this.isLeaf to get new value.
                        const {isLeaf} = this;

                        if (!isLeaf) this.handleExpand();
                        if (multiple) {
                            // if leaf sync checked state, else clear checked state
                            const checked = isLeaf ? node.checked : false;
                            this.handleMultiCheckChange(checked);
                        }
                    });
                } else {
                    panel.handleExpand(node);
                }
            },

            handleCheckChange() {
                const {panel, value, node} = this;
                panel.handleCheckChange(value);
                panel.handleExpand(node);
            },

            handleMultiCheckChange(checked) {
                this.node.doCheck(checked);
                this.panel.calculateMultiCheckedValue();
            },

            isInPath(pathNodes) {
                const {node} = this;
                const selectedPathNode = pathNodes[node.level - 1] || {};
                return selectedPathNode.uid === node.uid;
            },

            renderPrefix(h) {
                const {isLeaf, isChecked, config} = this;
                const {checkStrictly, multiple} = config;

                if (multiple) {
                    return this.renderCheckbox(h);
                } else if (checkStrictly) {
                    return this.renderRadio(h);
                } else if (isLeaf && isChecked) {
                    return this.renderCheckIcon(h);
                }

                return null;
            },

            renderPostfix(h) {
                const {node, isLeaf} = this;

                if (node.loading) {
                    return this.renderLoadingIcon(h);
                } else if (!isLeaf) {
                    return this.renderExpandIcon(h);
                }

                return null;
            },

            renderCheckbox(h) {
                const {node, config, isDisabled} = this;
                const events = {
                    on: {change: this.handleMultiCheckChange},
                    nativeOn: {}
                };

                if (config.checkStrictly) { // when every node is selectable, click event should not trigger expand event.
                    events.nativeOn.click = stopPropagation;
                }

                return (
                    < el - checkbox
                value = {node.checked
            }
                indeterminate = {node.indeterminate
            }
                disabled = {isDisabled}
                { ...
                    events
                }
            ><
                /el-checkbox>
            )
                ;
            },

            renderRadio(h) {
                let {checkedValue, value, isDisabled} = this;

                // to keep same reference if value cause radio's checked state is calculated by reference comparision;
                if (isEqual(value, checkedValue)) {
                    value = checkedValue;
                }

                return (
                    < el - radio
                value = {checkedValue}
                label = {value}
                disabled = {isDisabled}
                onChange = {this.handleCheckChange
            }
                nativeOnClick = {stopPropagation} >
                    {/* add an empty element to avoid render label */}
                    < span > < /span>
                    < /el-radio>
            )
                ;
            },

            renderCheckIcon(h) {
                return (
                    < i
            class
                = "el-icon-check el-cascader-node__prefix" > < /i>
            )
                ;
            },

            renderLoadingIcon(h) {
                return (
                    < i
            class
                = "el-icon-loading el-cascader-node__postfix" > < /i>
            )
                ;
            },

            renderExpandIcon(h) {
                return (
                    < i
            class
                = "el-icon-arrow-right el-cascader-node__postfix" > < /i>
            )
                ;
            },

            renderContent(h) {
                const {panel, node} = this;
                const render = panel.renderLabelFn;
                const vnode = render
                    ? render({node, data: node.data})
                    : null;

                return (
                    < span
            class
                = "el-cascader-node__label" > {vnode || node.label
            }<
                /span>
            )
                ;
            }
        },

        render(h) {
            const {
                inActivePath,
                inCheckedPath,
                isChecked,
                isLeaf,
                isDisabled,
                config,
                nodeId
            } = this;
            const {expandTrigger, checkStrictly, multiple} = config;
            const disabled = !checkStrictly && isDisabled;
            const events = {on: {}};

            if (expandTrigger === 'click') {
                events.on.click = this.handleExpand;
            } else {
                events.on.mouseenter = e => {
                    this.handleExpand();
                    this.$emit('expand', e);
                };
                events.on.focus = e => {
                    this.handleExpand();
                    this.$emit('expand', e);
                };
            }
            if (isLeaf && !isDisabled && !checkStrictly && !multiple) {
                events.on.click = this.handleCheckChange;
            }

            return (
                < li
            role = "menuitem"
            id = {nodeId}
            aria - expanded = {inActivePath}
            tabindex = {disabled ? null : -1}
        class
            = {
            {
                'el-cascader-node'
            :
                true,
                    'is-selectable'
            :
                checkStrictly,
                    'in-active-path'
            :
                inActivePath,
                    'in-checked-path'
            :
                inCheckedPath,
                    'is-active'
            :
                isChecked,
                    'is-disabled'
            :
                disabled
            }
        }
            {...
                events
            }
        >
            {
                this.renderPrefix(h)
            }
            {
                this.renderContent(h)
            }
            {
                this.renderPostfix(h)
            }
        <
            /li>
        )
            ;
        }
    };
</script>
